import type { ComponentStyleIdType } from '../../types/interfaces'
import type { ColorPickerProps } from './types'
import { UIComponent } from '../../lib/abstract'
import { ToolKit } from '../../lib/utils/toolkit'
import { ComponentStyleId } from '../../types/constants'
import { TextInput } from '../text_input'
import { styles } from './styles'
import { DEFAULT_COLOR_PICKER_PROPS, PRESET_COLORS } from './types'

export class ColorPicker extends UIComponent<ColorPickerProps> {
  id: string = 'color-picker'
  readonly description: string = '颜色取样器'
  readonly styleId: string = ComponentStyleId[this.name]
  readonly deFaultColor: string = '#000000'
  readonly deFaultText: string = '测试文本'
  element: JQuery<HTMLElement> | undefined = undefined

  get name(): ComponentStyleIdType {
    return 'ColorPicker'
  }

  get className(): string {
    return 'custom-color-picker'
  }

  constructor(props: ColorPickerProps) {
    super({
      ...DEFAULT_COLOR_PICKER_PROPS,
      ...props,
      presetColors: props.presetColors || PRESET_COLORS,
    })

    // 注册样式
    this.registerStyles()

    this.initColorDisplay()
  }

  ELEMENT_SELECTORS = {
    textInput: { selector: `#${this.props.id}-text`, dynamic: false, unique: true },
    colorInput: { selector: `#${this.props.id}-color`, dynamic: false, unique: true },
    colorPreview: { selector: `.color-input-container .color-preview`, dynamic: false, unique: false },
    colorValue: { selector: `.color-input-container .color-value`, dynamic: false, unique: false },
    switches: { selector: `.color-switch`, dynamic: false, unique: false },
  }

  getValue(): string | undefined {
    const $colorInput = this.getElement('colorInput')
    if (!$colorInput) {
      return undefined
    }
    return $colorInput.val() as string
  }

  /**
   * 初始化颜色显示
   */
  private initColorDisplay(): void {
    if (!this.props.value)
      return

    const handler = () => {
      const $container = $(`.${this.className} #${this.props.id}-color`).closest(`.${this.className}`)
      if ($container.length) {
        this.updateColor(
          this.props.value,
          this.getElement('colorPreview'),
          this.getElement('colorValue'),
          this.getElement('colorInput'),
        )
      }
    }

    ToolKit.async.waitForCondition(
      () => $(`.${this.className} #${this.props.id}-color`).closest(`.${this.className}`)?.length > 0,
      handler,
    )
  }

  render(): string {
    const { label } = this.props as ColorPickerProps

    return `
      <label>${label}</label>
      <div class="${this.className}">
        <div class="color-controls">
          <div class="text-input-container">
            ${this.renderTextInput()}
          </div>
          
          <div class="color-input-container">
            ${this.renderColorInput()}
          </div>
          
        </div>
        ${this.renderPreset()}
      </div>
    `
  }

  /**
   * 渲染文本输入框
   * @returns {string} 文本输入框 HTML
   */
  private renderTextInput(): string {
    const { id, text, textPlaceholder } = this.props

    return new TextInput({
      id: `${id}-text`,
      type: 'text',
      placeholder: textPlaceholder,
      value: text,
    }).render()
  }

  /**
   * 渲染颜色输入框
   * @returns {string} 颜色输入框 HTML
   */
  private renderColorInput(): string {
    const { id, value } = this.props
    const displayValue = value === 'transparent' ? '#FFFFFF' : value || this.deFaultColor

    return `
      <input 
        id="${id}-color" 
        type="color" 
        value="${displayValue}"
        data-real-value="${value || this.deFaultColor}"
      >
      <div 
        class="color-preview" 
        style="background-color: ${value || this.deFaultColor}"
        title="点击选择颜色"
      ></div>
      <div class="color-value" style="color: ${value} !important;">${this.deFaultText}</div>
    `
  }

  /**
   * 渲染预览颜色
   * @returns {string} 预览颜色HTML
   */
  private renderPreset(): string {
    const { showPresets, presetColors } = this.props as ColorPickerProps

    return `
      ${showPresets && presetColors && presetColors.length > 0
        ? `
          <div class="color-presets">
            ${presetColors.map(color => `
              <div 
                class="color-switch" 
                style="background-color: ${color}"
                data-color="${color}"
                title="${color}"
              ></div>
            `).join('')}
          </div>
        `
        : ''}
    `
  }

  /**
   * 处理文本变化逻辑
   * @param $textInput 文本输入框JQuery对象
   * @param $colorInput 颜色输入框JQuery对象
   * @param $colorPreview 颜色预览元素
   * @param $colorValue 颜色值显示元素
   * @param onTextChange 文本变化回调函数
   */
  private handleTextChange(
    $textInput: JQueryElement,
    $colorInput: JQueryElement,
    $colorPreview: JQueryElement,
    $colorValue: JQueryElement,
    onTextChange?: (text: string) => void,
  ): void {
    const newText = $textInput?.val() as string
    onTextChange?.(newText)

    // 如果文本是有效的 HEX 颜色，则更新颜色选择器
    if (/^#(?:[0-9A-F]{3}){1,2}$/i.test(newText)) {
      $colorInput?.val(newText)
      this.updateColor(newText, $colorPreview, $colorValue, $colorInput)
    }
  }

  bindEvents(): void {
    const { onChange, onTextChange } = this.props as ColorPickerProps
    const { textInput: $textInput, colorInput: $colorInput, colorValue: $colorValue, colorPreview: $colorPreview } = this.getElements()

    this.getElement('textInput')
      ?.on('blur', () => this.handleTextChange(
        $textInput as JQueryElement,
        $colorInput as JQueryElement,
        $colorPreview as JQueryElement,
        $colorValue as JQueryElement,
        onTextChange,
      ))
      .on('keydown', (e) => {
        if (e.key === 'Enter') {
          const $element = $(e.currentTarget)

          this.handleTextChange($element, $colorInput as JQueryElement, $colorPreview as JQueryElement, $colorValue as JQueryElement, onTextChange)
          $element.trigger('blur')
        }
      })

    // 颜色输入变化处理
    this.getElement('colorInput')?.on('input', (e) => {
      const $element = $(e.currentTarget)

      const realValue = $element.val() || $element.data('real-value')
      this.updateColor(realValue, this.getElement('colorPreview'), $colorValue as JQueryElement, $element)
      this.getElement('textInput')?.val(realValue)
      onChange?.(realValue)
    })

    // 预设颜色点击处理
    this.getElement('switches')?.on('click', (e) => {
      const color = $(e.currentTarget).data('color')
      if (color) {
        // 更新真实值
        this.getElement('colorInput')
          ?.val(color === 'transparent' ? '#FFFFFF' : color)
          .data('real-value', color)
        this.getElement('textInput')?.val(color)
        this.updateColor(color, this.getElement('colorPreview'), $colorValue as JQueryElement, $colorInput as JQueryElement)
        onChange?.(color)
      }
    })

    // 点击预览或值显示颜色选择器
    this.getElement('colorPreview')?.on('click', () => {
      this.getElement('colorInput')?.trigger('click')
    })
  }

  /**
   * 更新颜色显示
   * @param color 新颜色值
   * @param $preview 预览元素
   * @param $value 颜色值显示元素
   * @param $input 颜色输入框元素
   */
  private updateColor(
    color: string,
    $preview: JQueryElement,
    $value: JQueryElement,
    $input: JQueryElement,
  ): void {
    // 保存真实值到data属性
    $input?.data('real-value', color)

    // 特殊处理透明色
    if (color === 'transparent') {
      $preview?.css({
        'background-color': 'transparent',
        'background-image': 'linear-gradient(45deg, #ddd 25%, transparent 25%), linear-gradient(-45deg, #ddd 25%, transparent 25%), linear-gradient(45deg, transparent 75%, #ddd 75%), linear-gradient(-45deg, transparent 75%, #ddd 75%)',
        'background-size': '16px 16px',
        'background-position': '0 0, 0 8px, 8px -8px, -8px 0px',
      })
    }
    else {
      $preview?.css({
        'background-color': color,
        'background-image': 'none',
      })
    }

    // 更新文本颜色（透明色显示为黑色）
    $value && $value[0]?.style.setProperty(
      'color',
      color === 'transparent' ? '#000000' : color,
      'important',
    )
  }

  reset(): void {
    super.reset()

    // 1. 重置文本输入
    this.getElement('textInput')?.val('').trigger('blur')

    // 2. 重置颜色值
    const defaultValue = this.deFaultColor
    this.getElement('colorInput')
      ?.val(defaultValue === 'transparent' ? '#FFFFFF' : defaultValue)
      .data('real-value', defaultValue)

    // 3. 更新UI状态
    this.updateColor(
      defaultValue,
      this.getElement('colorPreview'),
      this.getElement('colorValue'),
      this.getElement('colorInput'),
    )
  }

  destroy(): void {
    super.destroy()
  }

  getStyles(): string {
    return styles()
  }
}
